{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "| 时代          | 分类                | 特性 / 语法                                                  | 标准 / 状态      | 作用                                 | 典型场景 / 备注                                 |\n",
    "| ------------- | ------------------- | ------------------------------------------------------------ | ---------------- | ------------------------------------ | ----------------------------------------------- |\n",
    "| C++98 / C++03 | 标准保证            | `operator new` / `std::malloc`                               | 标准             | 返回指针满足平台默认“最大标量对齐”   | 不能显式查询或提升对齐；仅依赖默认设置          |\n",
    "| C++98 / C++03 | 标准保证            | 对象布局规则（natural alignment）                            | 标准             | 确保对象按自身自然对齐布局           | 无法通过语法改变或查询对齐                      |\n",
    "| C++98 / C++03 | 标准保证            | `#pragma pack`                                               | 非标准扩展       | 降低结构体对齐，获得紧凑布局         | 常用于 ABI 兼容；可能带来性能损失或 UB          |\n",
    "| C++98 / C++03 | 编译器扩展          | `__attribute__((aligned(n)))`                                | GCC / Clang 扩展 | 提升变量或类型对齐                   | SIMD 数据、手写内存结构；不可移植               |\n",
    "| C++98 / C++03 | 编译器扩展          | `__declspec(align(n))`                                       | MSVC 扩展        | 提升变量或类型对齐                   | SSE/AVX 数据结构；Windows 专用                  |\n",
    "| C++98 / C++03 | 编译器扩展          | 其他厂商扩展（ICC 等）                                       | 各家扩展         | 通常与 GCC 属性兼容                  | 仍需条件编译，缺乏统一接口                      |\n",
    "| C++98 / C++03 | 手工技巧            | 手动计算对齐指针                                             | 通用做法         | malloc 较大空间后自行调整地址        | 需存储原始指针以便释放；易出错                  |\n",
    "| C++11         | 关键字 / 运算符     | `alignas(expr)`                                              | 标准             | 提升变量、对象或类型的对齐要求       | SIMD、缓存行对齐、硬件寄存器映射                |\n",
    "| C++11         | 关键字 / 运算符     | `alignof(T)`                                                 | 标准             | 获取类型 `T` 的对齐值                | 编译期查询、静态断言、模板元编程                |\n",
    "| C++11         | 类型 / 别名         | `std::alignment_of<T>`                                       | 标准             | type trait 版 `alignof`              | 模板元编程按对齐分支                            |\n",
    "| C++11 / C++14 | 类型 / 别名         | `std::aligned_storage<N, A>` / `_t`                          | 标准             | 提供大小 `N`、对齐 `A` 的原始缓冲区  | 手写内存池、类型擦除缓冲区                      |\n",
    "| C++11 / C++14 | 类型 / 别名         | `std::aligned_union<N, Ts...>` / `_t`（C++23 弃用）          | 标准             | 为若干类型提供统一对齐存储           | `union` 风格类型擦除（建议改用 `std::variant`） |\n",
    "| C++11         | 类型 / 别名         | `std::max_align_t`                                           | 标准             | 具备平台常用最大对齐的类型           | 通用缓冲区、跨类型存储                          |\n",
    "| C++17         | 函数                | `std::align`                                                 | 标准             | 在缓冲区中向上对齐指针并更新剩余空间 | 自定义分配器、内存池切片                        |\n",
    "| C++17         | 函数                | `std::launder`                                               | 标准             | 同址重建对象后获取合法指针           | placement new、多次构造、内存池管理             |\n",
    "| C++17         | 函数                | `std::destroy_at`                                            | 标准             | 显式析构对象                         | 自定义容器、对象池                              |\n",
    "| C++17         | 函数                | `std::aligned_alloc`                                         | 标准（C 接口）   | 分配满足指定对齐的堆内存             | 跨语言交互、自定义对齐分配                      |\n",
    "| C++17         | `operator new` 扩展 | `void* operator new(std::size_t, std::align_val_t)` 等       | 标准             | 支持高对齐分配/释放                  | AVX-512 对象、设备接口                          |\n",
    "| C++17         | 杂项常量            | `std::hardware_destructive_interference_size` / `constructive_interference_size` | 标准             | 提供缓存行大小提示                   | 多线程共享 / 避免伪共享的数据布局               |\n",
    "| C++20         | 辅助概念            | `std::bit_cast`                                              | 标准             | 要求大小/对齐一致的位级复制          | 安全重解释类型、序列化 / 反序列化               |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- `alignas` / `alignof`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "alignof(SimdVector) = 32\n",
      "Address             = 0x7ffe36c5d7a0\n",
      "Is 32-byte aligned? yes\n",
      "\n",
      "alignof(values)     = 8\n",
      "Address             = 0x7ffe36c5d780\n",
      "Is 16-byte aligned? yes\n"
     ]
    }
   ],
   "source": [
    "#include <cstdint>\n",
    "#include <iostream>\n",
    "\n",
    "struct alignas(32) SimdVector {\n",
    "  float data[8];\n",
    "};\n",
    "\n",
    "{\n",
    "  SimdVector v{};\n",
    "  std::uintptr_t addr = reinterpret_cast<std::uintptr_t>(&v);\n",
    "\n",
    "  std::cout << \"alignof(SimdVector) = \" << alignof(SimdVector) << '\\n';\n",
    "  std::cout << \"Address             = \" << &v << '\\n';\n",
    "  std::cout << \"Is 32-byte aligned? \" << ((addr % 32 == 0) ? \"yes\" : \"no\") << '\\n';\n",
    "\n",
    "  alignas(16) double values[2] = {};\n",
    "  addr = reinterpret_cast<std::uintptr_t>(values);\n",
    "\n",
    "  std::cout << \"\\nalignof(values)     = \" << alignof(decltype(values)) << '\\n';\n",
    "  std::cout << \"Address             = \" << values << '\\n';\n",
    "  std::cout << \"Is 16-byte aligned? \" << ((addr % 16 == 0) ? \"yes\" : \"no\") << '\\n';\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- `std::alignment_of<T>`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "#include <iostream>\n",
    "#include <type_traits>\n",
    "#include <cstddef>\n",
    "\n",
    "template <typename T>\n",
    "void print_alignment(const char* name) {\n",
    "  std::cout << name << \": alignof = \" << alignof(T)\n",
    "            << \", std::alignment_of = \" << std::alignment_of<T>::value << '\\n';\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "char: alignof = 1, std::alignment_of = 1\n",
      "double: alignof = 8, std::alignment_of = 8\n",
      "long double: alignof = 16, std::alignment_of = 16\n",
      "std::max_align_t: alignof = 16, std::alignment_of = 16\n"
     ]
    }
   ],
   "source": [
    "{\n",
    "  print_alignment<char>(\"char\");\n",
    "  print_alignment<double>(\"double\");\n",
    "  print_alignment<long double>(\"long double\");\n",
    "  print_alignment<std::max_align_t>(\"std::max_align_t\");\n",
    "\n",
    "  static_assert(std::alignment_of<long double>::value == alignof(long double),\n",
    "                \"alignment_of must equal alignof\");\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- `std::aligned_storage`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Gadget(42, Flux Capacitor) constructed\n",
      "Stored gadget at 0x7fffc2cf5260, alignof(Gadget) = 8\n",
      "Gadget(42, Flux Capacitor) destroyed\n"
     ]
    }
   ],
   "source": [
    "#include <iostream>\n",
    "#include <new>\n",
    "#include <string>\n",
    "#include <type_traits>\n",
    "\n",
    "struct Gadget {\n",
    "  Gadget(int id, std::string name) : id(id), name(name) {\n",
    "    std::cout << \"Gadget(\" << id << \", \" << name << \") constructed\\n\";\n",
    "  }\n",
    "  ~Gadget() {\n",
    "    std::cout << \"Gadget(\" << id << \", \" << name << \") destroyed\\n\";\n",
    "  }\n",
    "\n",
    "  int id;\n",
    "  std::string name;\n",
    "};\n",
    "\n",
    "{\n",
    "  typedef std::aligned_storage<sizeof(Gadget), alignof(Gadget)>::type Buffer;\n",
    "  Buffer storage;\n",
    "\n",
    "  Gadget* ptr = new (&storage) Gadget(42, \"Flux Capacitor\");\n",
    "  std::cout << \"Stored gadget at \" << static_cast<void*>(ptr)\n",
    "            << \", alignof(Gadget) = \" << alignof(Gadget) << '\\n';\n",
    "\n",
    "  ptr->~Gadget();\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- ~~`std::aligned_union`~~~~"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "A.a = 123\n",
      "B.b = 3.14159\n",
      "sizeof(Storage) = 8\n",
      "alignment       = 8\n"
     ]
    }
   ],
   "source": [
    "#include <cstring>\n",
    "#include <iostream>\n",
    "#include <type_traits>\n",
    "\n",
    "struct A { int a; };\n",
    "struct B { double b; };\n",
    "\n",
    "{\n",
    "  typedef std::aligned_union<0, A, B>::type Storage;\n",
    "\n",
    "  Storage storage;\n",
    "  void* raw = &storage;\n",
    "\n",
    "  // 在同一缓冲区依次放置 A 和 B\n",
    "  A* pa = new (raw) A{123};\n",
    "  std::cout << \"A.a = \" << pa->a << '\\n';\n",
    "  pa->~A();\n",
    "\n",
    "  B* pb = new (raw) B{3.14159};\n",
    "  std::cout << \"B.b = \" << pb->b << '\\n';\n",
    "  pb->~B();\n",
    "\n",
    "  std::cout << \"sizeof(Storage) = \" << sizeof(Storage) << '\\n';\n",
    "  std::cout << \"alignment       = \" << alignof(Storage) << '\\n';\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- `std::max_align_t`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "alignof(std::max_align_t) = 16\n",
      "Buffer address             = 0x7fffc2cf5240\n",
      "Is max-align aligned?      yes\n"
     ]
    }
   ],
   "source": [
    "#include <cstddef>\n",
    "#include <cstdint>\n",
    "#include <iostream>\n",
    "\n",
    "{\n",
    "  std::cout << \"alignof(std::max_align_t) = \" << alignof(std::max_align_t) << '\\n';\n",
    "\n",
    "  alignas(std::max_align_t) unsigned char buffer[64];\n",
    "  std::uintptr_t addr = reinterpret_cast<std::uintptr_t>(buffer);\n",
    "\n",
    "  std::cout << \"Buffer address             = \" << static_cast<void*>(buffer) << '\\n';\n",
    "  std::cout << \"Is max-align aligned?      \"\n",
    "            << ((addr % alignof(std::max_align_t) == 0) ? \"yes\" : \"no\") << '\\n';\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# C++ 结构体 / 类的字节对齐"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "1. **`offsetof` 限制**：仅能应用于标准布局类型；否则行为未定义。\n",
    "2. **位域（bit-field）**：编译器根据实现决定排列与压缩方式，难以跨平台依赖。\n",
    "3. **`#pragma pack`**：会降低对齐要求，谨慎使用；常用于与外部二进制协议对接，需配合 `static_assert(sizeof(T) == expected)`。\n",
    "4. **`[[no_unique_address]]`（C++20）**：可消除空基类成员的额外开销（需注意 ABI 差异）。\n",
    "5. **跨平台差异**：不同 ABI、编译器对结构体布局细节可能不同，尤其是虚继承、位域、`long double` 等。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 基本概念\n",
    "\n",
    "| 名称              | 说明                                                         | 常见结论                                      |\n",
    "| ----------------- | ------------------------------------------------------------ | --------------------------------------------- |\n",
    "| 对齐（alignment） | 对象地址必须是某个 2 的幂的倍数。                            | `alignof(T)` 返回类型 `T` 的对齐要求。        |\n",
    "| 填充（padding）   | 编译器插入的空字节，使后续成员满足对齐。                     | 可能存在 **成员间填充** 与 **结构尾部填充**。 |\n",
    "| 结构体总对齐      | 等于其所有成员与基类对齐要求的最大值。                       | `alignof(Struct) = max(alignof(成员...))`。   |\n",
    "| 结构体大小        | 大于等于成员实际占用；编译器会向上取整到 `alignof(Struct)` 的倍数。 | 常导致尾部填充。                              |\n",
    "\n",
    "> ✅ 在标准布局（standard-layout）类型中：非静态成员按声明顺序排列，但编译器可插入 padding。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 结构体布局规则简述\n",
    "\n",
    "1. **每个成员起始地址**必需满足该成员类型的对齐要求。\n",
    "2. 为满足某成员的对齐要求，编译器可以在前一个成员之后插入 padding。\n",
    "3. 整个结构体的大小会被补齐，确保多个结构体元素组成数组时，每个元素也满足对齐。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 分析步骤与工具\n",
    "\n",
    "| 步骤            | 方法                                                         | 工具 / 技术                                  |\n",
    "| --------------- | ------------------------------------------------------------ | -------------------------------------------- |\n",
    "| 1. 获取整体信息 | `sizeof(T)`、`alignof(T)`                                    | 编译期常量，可配合 `static_assert` 。        |\n",
    "| 2. 查看成员偏移 | `offsetof(T, member)`（`<cstddef>`）                         | 只能用于标准布局类型；结果为 `std::size_t`。 |\n",
    "| 3. 验证排列顺序 | 使用 `static_assert(offsetof(T, b) == 8)` 等                 | 可确保 ABI 不变。                            |\n",
    "| 4. 编译器警告   | `-Wpadded`（GCC/Clang）                                      | 对潜在 padding 发出警告。                    |\n",
    "| 5. 查看详细布局 | `-fdump-record-layouts`（Clang）或 `/d1reportSingleClassLayout`（MSVC） | 输出成员偏移、基类布局。                     |\n",
    "| 6. 手工可视化   | 运行时代码打印内存偏移、十六进制内容                         | 仅用于调试验证。                             |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 成员排序影响布局（C++11）\n",
    "  - `a` 占 1 字节；为了让 `b` 满足 4 字节对齐，编译器在 `a` 后插入 3 字节 padding。\n",
    "  - `b` 从偏移 4 开始，结束后立即放置 `c`（偏移 8）。\n",
    "  - 结构体最大对齐为 4，`sizeof(A)` 会向上取整到 4 的倍数（结果 12，尾部再填充 2 字节）。\n",
    "\n",
    "> 通过调整成员顺序（先放 `b`）可减少 padding。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "sizeof(A)  = 12\n",
      "alignof(A) = 4\n",
      "offsetof(A, a) = 0\n",
      "offsetof(A, b) = 4\n",
      "offsetof(A, c) = 8\n"
     ]
    }
   ],
   "source": [
    "#include <cstddef>\n",
    "#include <cstdint>\n",
    "#include <iostream>\n",
    "\n",
    "struct A {\n",
    "  std::uint8_t  a;  // 1 byte\n",
    "  std::uint32_t b;  // 4 bytes, needs 4-byte alignment\n",
    "  std::uint16_t c;  // 2 bytes, needs 2-byte alignment\n",
    "};\n",
    "\n",
    "{\n",
    "  std::cout << \"sizeof(A)  = \" << sizeof(A) << '\\n';\n",
    "  std::cout << \"alignof(A) = \" << alignof(A) << '\\n';\n",
    "\n",
    "  std::cout << \"offsetof(A, a) = \" << offsetof(A, a) << '\\n';\n",
    "  std::cout << \"offsetof(A, b) = \" << offsetof(A, b) << '\\n';\n",
    "  std::cout << \"offsetof(A, c) = \" << offsetof(A, c) << '\\n';\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 标准布局 + `static_assert` 守护"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "#include <cstddef>\n",
    "#include <cstdint>\n",
    "#include <type_traits>\n",
    "\n",
    "struct Header {\n",
    "  std::uint32_t type; // 4\n",
    "  std::uint16_t version; // 2\n",
    "  std::uint16_t flags; // 2\n",
    "};\n",
    "\n",
    "static_assert(std::is_standard_layout<Header>::value, \"Header must be standard layout\");\n",
    "static_assert(sizeof(Header) == 8, \"Unexpected header size\");\n",
    "static_assert(alignof(Header) == alignof(std::uint32_t), \"Alignment must equal max member\");\n",
    "static_assert(offsetof(Header, type) == 0, \"ABI changed\");\n",
    "static_assert(offsetof(Header, version) == 4, \"ABI changed\");\n",
    "\n",
    "// 在需要 16 字节对齐的地方使用 wrapper\n",
    "struct alignas(16) HeaderAligned : Header {};\n",
    "static_assert(sizeof(HeaderAligned) == 16, \"Aligned wrapper size mismatch\");\n",
    "static_assert(alignof(HeaderAligned) == 16, \"Aligned wrapper alignment mismatch\");\n",
    "\n",
    "{\n",
    "  alignas(16) Header buffer[4];      // 数组元素对齐为 16\n",
    "  HeaderAligned aligned{};           // 也满足 16 字节对齐\n",
    "  (void)buffer;\n",
    "  (void)aligned;\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 类继承与虚函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "sizeof(Base)    = 16\n",
      "alignof(Base)   = 8\n",
      "sizeof(Derived) = 24\n",
      "alignof(Derived)= 8\n",
      "offset of y     = 16\n"
     ]
    }
   ],
   "source": [
    "#include <cstddef>\n",
    "#include <cstdint>\n",
    "#include <iostream>\n",
    "\n",
    "struct Base {\n",
    "  int x;\n",
    "  virtual void foo() {}\n",
    "};\n",
    "\n",
    "struct Derived : Base {\n",
    "  double y;\n",
    "};\n",
    "\n",
    "{\n",
    "  Derived d{};\n",
    "  std::uintptr_t base = reinterpret_cast<std::uintptr_t>(&d);\n",
    "  std::uintptr_t member = reinterpret_cast<std::uintptr_t>(&d.y);\n",
    "\n",
    "  std::cout << \"sizeof(Base)    = \" << sizeof(Base) << '\\n';\n",
    "  std::cout << \"alignof(Base)   = \" << alignof(Base) << '\\n';\n",
    "  std::cout << \"sizeof(Derived) = \" << sizeof(Derived) << '\\n';\n",
    "  std::cout << \"alignof(Derived)= \" << alignof(Derived) << '\\n';\n",
    "  std::cout << \"offset of y     = \" << (member - base) << '\\n';\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    " - `offsetof` 宏的限制：**它只能用于标准布局（standard-layout）类型**。\n",
    "- 标准要求里有几条只要触犯任意一条就“非标准布局”，其中一条是：类中含有虚函数或虚基类 ⇒ 非标准布局"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 编译阶段输出完整布局"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "| 编译器                    | 选项 / 工具                                  | 作用                                                         | 输出位置 / 形式                      | 适用场景与备注                                               |\n",
    "| ------------------------- | -------------------------------------------- | ------------------------------------------------------------ | ------------------------------------ | ------------------------------------------------------------ |\n",
    "| Clang                     | `-Xclang -fdump-record-layouts`              | 输出每个 `struct` / `class` 的成员偏移、大小、对齐、虚表信息。 | 直接打印到编译器标准输出。           | 适用于分析任意类型（含模板实例）。可搭配 `-Xclang -fdump-record-layouts-simple` 获得精简格式。 |\n",
    "| Clang / GCC               | `-Wpadded`                                   | 对因对齐插入的 padding 发出警告。                            | 编译器警告信息。                     | 帮助定位成员间或尾部 padding，常与 `static_assert`、`sizeof` 等搭配使用。 |\n",
    "| GCC                       | `-fdump-lang-class`(代替了`-fdump-class-hierarchy`)                     | 报告类层次、虚表、对象大小与成员偏移（主要针对含继承/虚函数的类型）。 | 生成 `源文件名.class` 文本文件。     | 默认对纯 POD 结构体信息有限；分析虚函数、虚基类、继承布局时非常有用。 |\n",
    "| GCC                       | `-fdump-ipa-class-hierarchy`                 | 链接期的类层次调试信息，包含优化阶段的合并情况。             | 生成 `源文件名.ipa-class` 文本文件。 | 较少用，仅在需要深入了解 IPO（跨过程优化）阶段布局时启用。   |\n",
    "| GCC / Clang（需额外工具） | `pahole`（与 `-g` 编译后的目标文件配合使用） | 基于 DWARF 调试信息列出结构体成员偏移、大小、padding。       | `pahole <object>` 命令输出。         | 适用于 POD 类型或需要统一查看多个结构的情况；不是编译器选项，但常与 GCC/Clang 配合。 |\n",
    "| MSVC                      | `/d1reportSingleClassLayout<Type>`           | 输出指定类型的成员偏移、大小、虚表、继承信息。               | 编译输出窗口（或命令行）。           | 可同时指定多个类型，如 `/d1reportSingleClassLayoutBase /d1reportSingleClassLayoutDerived`。类型名需精确匹配（模板需写出实例）。 |\n",
    "| MSVC                      | `/Wall`（或更具体的 `/wd`/`/we` 控制）       | 发出包括 padding 在内的额外警告（MSVC 对 padding 的特定警告号为 C4820）。 | 编译器警告信息。                     | 可用 `/wd4820` 关闭，或 `/we4820` 设为错误。通常与 `/d1reportSingleClassLayout` 搭配使用。 |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "组合建议：\n",
    "\n",
    "- **布局总览**：Clang 用 `-fdump-record-layouts`；MSVC 用 `/d1reportSingleClassLayout`；GCC 用 `-fdump-lang-class`（若需 POD 详情，可额外用 `pahole`）。\n",
    "- **快速发现 padding**：所有编译器上启用 `-Wpadded`（Clang/GCC）/ `C4820`（MSVC）。\n",
    "- **保持 ABI 稳定**：搭配 `sizeof` / `alignof` / `offsetof` + `static_assert`。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# GCC"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {
    "vscode": {
     "languageId": "shellscript"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Vtable for Base\n",
      "Base::_ZTV4Base: 3 entries\n",
      "0     (int (*)(...))0\n",
      "8     (int (*)(...))(& _ZTI4Base)\n",
      "16    (int (*)(...))Base::foo\n",
      "\n",
      "Class Base\n",
      "   size=16 align=8\n",
      "   base size=12 base align=8\n",
      "Base (0x0x7819c7550420) 0\n",
      "    vptr=((& Base::_ZTV4Base) + 16)\n",
      "\n",
      "Vtable for Derived\n",
      "Derived::_ZTV7Derived: 3 entries\n",
      "0     (int (*)(...))0\n",
      "8     (int (*)(...))(& _ZTI7Derived)\n",
      "16    (int (*)(...))Base::foo\n",
      "\n",
      "Class Derived\n",
      "   size=24 align=8\n",
      "   base size=24 base align=8\n",
      "Derived (0x0x7819c740e1a0) 0\n",
      "    vptr=((& Derived::_ZTV7Derived) + 16)\n",
      "Base (0x0x7819c75505a0) 0\n",
      "      primary-for Derived (0x0x7819c740e1a0)\n",
      "\n"
     ]
    }
   ],
   "source": [
    "! cd virtual && gcc -std=c++17 -fdump-lang-class -c virtual.cpp && cat virtual.cpp.001l.class"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "shellscript"
    }
   },
   "outputs": [],
   "source": [
    "! cd virtual && gcc -std=c++17 -fdump-tree-all -c virtual.cpp "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "shellscript"
    }
   },
   "outputs": [],
   "source": [
    "! cd virtual && gcc -std=c++17 -fdump-tree-gimple -c virtual.cpp "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "vscode": {
     "languageId": "shellscript"
    }
   },
   "outputs": [],
   "source": [
    "! cd virtual && g++ -std=c++17 -fdump-lang-all -c virtual.cpp"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Clang"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "struct Base {\n",
    "  int x;\n",
    "  virtual void foo() {}          // 定义放在类内 → 内联 → Base 没有 key function\n",
    "};\n",
    "\n",
    "struct Derived : Base {\n",
    "  double y;\n",
    "};"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`-fdump-vtable-layouts`（以及 `-fdump-vtable-layouts-simple`）只有在 **Clang 实际决定要生成该类的虚表** 时才会输出内容；如果编译过程停在语义分析阶段（`-fsyntax-only`），并且这个类没有「关键虚函数（key function）」或没有被 ODR-use，就不会触发虚表生成，因此也就没有任何 dump。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "// https://gcc.godbolt.org/z/PbahWvz4q\n",
    "\n",
    "struct Base {\n",
    "    int x;\n",
    "    virtual void foo() {}\n",
    "};\n",
    "\n",
    "struct Derived : Base {\n",
    "    double y;\n",
    "};\n",
    "\n",
    "Derived force_use;           // 全局对象，同样会触发行布局和虚表生成"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "C++17",
   "language": "C++17",
   "name": "xcpp17"
  },
  "language_info": {
   "codemirror_mode": "text/x-c++src",
   "file_extension": ".cpp",
   "mimetype": "text/x-c++src",
   "name": "c++",
   "version": "17"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
